#define HLS_C
/*----------------------------------------------*
 * include files            	 ������ͷ�ļ�   *
 *----------------------------------------------*/
#if defined(OS_ANDROID)||defined(OS_LINUX_SOC)	
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <err.h>
#elif defined(OS_WIN32)
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
//user header
#include <libmscommon/msstring.h>
#include <libmscommon/msnetwork.h>
#include <libmscommon/mstime.h>
#include <libmscommon/msepoll.h>
#include <libmslog/mslog.h>
#include "msprotocol.h"

 #define FLAG "HLS"
 /*---------以下配置不要轻易修改--------------------*/
//读取
#define HLSIN_PARASEM3U8_INTERVALTIME	4	 	//读取m3u8文件的间隔，单位秒
#define HLSIN_MAX_XSTREAM	20	 				//最大支持XSTREAM个数
//生成
 #define HLSOUT_SEGMENT_URLLEN			128		//生成的切片URL长度
 #define HLSOUT_SEGMENT_RESNUM			4		//切片过期保留的数量，可以有效避免404播放问题
 #define HLSOUT_SEGMENT_TOTALNUM(list_size)		(list_size+HLSOUT_SEGMENT_RESNUM)		//切片总数
 #define HLSOUT_SEGMENT_LISTSIZE(list_size)		(1+HLSOUT_SEGMENT_TOTALNUM(list_size)) 	
 #define HLSOUT_SEGMENTING_INM3U8	ms_false	 //M3U8文件中是否包含正在生成的切

 /*---------调试功能--------------------*/
 #define DBG_HLS				ms_false
 #define DBG_HLSIN_READ			ms_false
 #define DBG_HLSIN_XSTREAM		ms_true
 #define DBG_HLSIN_PLAYLIST		ms_false
 #if DBG_HLSIN_PLAYLIST
  	#define hlsin_msm3u8_maxsegment		30
 #else
  	#define hlsin_msm3u8_maxsegment		4096
 #endif
 #define DBG_HLSIN_PLAYLISTINFO		ms_false
 #define DBG_HLSIN_PLAYLISTIN		ms_false
 #define DBG_HLSIN_PLAYLISTOUT		ms_false

 #define DBG_HLSOUT_PLAYLIST			ms_false
 #if DBG_HLSOUT_PLAYLIST
	#define msm3u8_maxsqencenum	(20)
 #else
	#define msm3u8_maxsqencenum	(ms_f32-5)
 #endif
#define DBG_HLSOUT_PLAYLISTINFO	ms_false
 
typedef struct HLSPlaylist{
	ms_u64 time_us;
	ms_u08 url[512];
	ms_u32 mediasequence;
 }HLSPlaylist;

typedef struct HLSXSTREAMContext {
	ms_byte resolution[64];
	ms_byte codes[128];
	ms_double frame_rate;
	ms_u32 average_bandwidth;
	ms_u32 bandwidth;
	ms_byte url[1024];
}HLSXSTREAMContext;
typedef struct HLSContext {
//common
	URLContext urlctt_m3u8;		//获取M3U8文件的上下文
	URLContext urlctt_segment;	//获取切片文件的上下文
	ms_u08 path[mscfg_maxlen_url];	//输入-URL地址的前缀;输出-输出目录(dir);
	ms_u32 version;				//M3U8文件版本号
	ms_bool allowcache;			//M3U8文件allowcache
	ms_u32 list_size;			//M3U8文件中放几个切片
	float time;					//输入-targetduration,输出-切片时间
	ms_u64 time_us;				//输入-targetduration,输出-切片时间
	ms_u32 segment_head;		//mediasequence
	ms_byte hls_info[256];		//调试信息
//in
	ms_u64 timep_m3u8Parse;
	URLProtocol *ptlHttp;
	URLInfo path_info;//set by call 	
	ms_u32 segment_excpect;	//mediasequence
	//
	ms_bool flag_cmdstop_m3u8Parase;
	MSTHREADContext tdM3u8Parase;
	//xstream
	ms_bool flag_hasxstream;
	ms_u32 xstream_num;
	HLSXSTREAMContext xstrem_ctt[HLSIN_MAX_XSTREAM];
	
	ms_u64 recv_time_base;
	ms_u32 recv_segment_len;
	ms_u32 playlist_index_out;
	ms_u32 playlist_index_stand;	
	ms_u32 playlist_index_in;
	ms_u32 playlist_totalnum;
	//segment list
	HLSPlaylist *playlist;
	HLSPlaylist *pplaylist_cur;
	HLSPlaylist *pphlsctt_pre;
	ms_bool flag_finished;
	ms_u08 unvalidplaylist_num;
//out	
	ms_u64 timep_newsegment;
	URLProtocol *ptlfile;
	ms_u08 *list_segment;
	ms_u08 segment_delete;
	ms_u08 programname[128];
	ms_u32 segment_tail;
	ms_bool flag_started_list;
	ms_bool flag_next;	//读取下一个分片
} HLSContext;

#define m3u8_tag				"#EXTM3U"
#define m3u8_ver				"#EXT-X-VERSION"
#define m3u8_allowCache			"#EXT-X-ALLOW-CACHE"
#define m3u8_targetDuration		"#EXT-X-TARGETDURATION"
#define m3u8_mediaSequence		"#EXT-X-MEDIA-SEQUENCE"
#define m3u8_media				"#EXT-X-MEDIA"
#define m3u8_streamInf			"#EXT-X-STREAM-INF"
//EXTINF floating point durations
#define m3u8_inf				"#EXTINF"
//#EXT-X-PROGRAM-DATE-TIME:2021-06-15T08:28:50.921Z
#define m3u8_programDataTime	"#EXT-X-PROGRAM-DATE-TIME"
#define m3u8_endList			"#EXT-X-ENDLIST"

/*
#EXTM3U
#EXT-X-VERSION:5
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="English stereo",LANGUAGE="en",AUTOSELECT=YES,URI="f08e80da-bf1d-4e3d-8899-f0f6155f6efa_audio_1_stereo_128000.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=628000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=320x180,AUDIO="audio"
f08e80da-bf1d-4e3d-8899-f0f6155f6efa_video_180_250000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=928000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=480x270,AUDIO="audio"
f08e80da-bf1d-4e3d-8899-f0f6155f6efa_video_270_400000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1728000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=640x360,AUDIO="audio"
f08e80da-bf1d-4e3d-8899-f0f6155f6efa_video_360_800000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2528000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=960x540,AUDIO="audio"
f08e80da-bf1d-4e3d-8899-f0f6155f6efa_video_540_1200000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=4928000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=1280x720,AUDIO="audio"
f08e80da-bf1d-4e3d-8899-f0f6155f6efa_video_720_2400000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=9728000,CODECS="avc1.42c00d,mp4a.40.2",RESOLUTION=1920x1080,AUDIO="audio"
f08e80da-bf1d-4e3d-8899-f0f6155f6efa_video_1080_4800000.m3u8

#EXTM3U
#EXT-X-STREAM-INF:RESOLUTION=1280x720,FRAME-RATE=29.970,CODECS="avc1.4d001f,mp4a.40.2",AVERAGE-BANDWIDTH=2710000,BANDWIDTH=3390000
tracks-v1a1/mono.m3u8
#EXT-X-STREAM-INF:RESOLUTION=1024x576,FRAME-RATE=29.970,CODECS="avc1.4d001f,mp4a.40.2",AVERAGE-BANDWIDTH=1690000,BANDWIDTH=2110000
tracks-v2a1/mono.m3u8


#EXTM3U                                                                                                                                                                                                              
#EXT-X-VERSION:3                                                                                                                                                                                                     
#EXT-X-ALLOW-CACHE:YES                                                                                                                                                                                               
#EXT-X-TARGETDURATION:5                                                                                                                                                                                              
#EXT-X-MEDIA-SEQUENCE:36                                                                                                                                                                                             
#EXTINF:5.000000,                                                                                                                                                                                                    
336.ts                                                                                                                                                                                                               
#EXT-X-MEDIA-SEQUENCE:37                                                                                                                                                                                             
#EXTINF:5.000000,                                                                                                                                                                                                    
337.ts                                                                                                                                                                                                               
#EXT-X-MEDIA-SEQUENCE:38                                                                                                                                                                                             
#EXTINF:5.000000,                                                                                                                                                                                                    
338.ts                                                                                                                                                                                                               
#EXT-X-MEDIA-SEQUENCE:39                                                                                                                                                                                             
#EXTINF:5.000000,                                                                                                                                                                                                    
339.ts                                                                                                                                                                                                               
#EXT-X-MEDIA-SEQUENCE:40                                                                                                                                                                                             
#EXTINF:5.000000,                                                                                                                                                                                                    
340.ts  

*/
/*
in:hls_innerapi_m3u8Parase		-->segment in 
out:hls_innerapi_playlistOut		-->segment out 
total:hls_innerapi_playlistGetNum	-->segment total 
*/
static void hls_innerapi_playlistPrintInfo(HLSContext * phlsctt)
{
	int index=0;
	int index_list=0;
	ms_info("-----------------------------------valid list:%d",phlsctt->playlist_totalnum);
	for(index=phlsctt->playlist_index_out;index<(phlsctt->playlist_index_out+phlsctt->playlist_totalnum);index++){
		 if(ms_noLess(index, hlsin_msm3u8_maxsegment)){
			index_list=index-hlsin_msm3u8_maxsegment;
		}else{
			index_list=index;
		}
		ms_info("%04d-%d-%s-%s",index_list,phlsctt->playlist[index_list].mediasequence,ms_num2str( phlsctt->playlist[index_list].time_us),phlsctt->playlist[index_list].url);
	}
	ms_info("-----------------------------------");
	if (hlsin_msm3u8_maxsegment<20){
		ms_info("-----------------------------------all list,valid list:%d",phlsctt->playlist_totalnum);
		for(index=0;index<hlsin_msm3u8_maxsegment;index++){
			 if(ms_noLess(index, hlsin_msm3u8_maxsegment)){
				index_list=index-hlsin_msm3u8_maxsegment;
			}else{
				index_list=index;
			}
			if(index_list==phlsctt->playlist_index_stand){
				ms_info("[s]%04d-%d-%s-%s",index_list,phlsctt->playlist[index_list].mediasequence,ms_num2str(  phlsctt->playlist[index_list].time_us),phlsctt->playlist[index_list].url);
			}
			if(index_list==phlsctt->playlist_index_in){
				ms_info("[i]%04d-%d-%s-%s",index_list,phlsctt->playlist[index_list].mediasequence,ms_num2str(  phlsctt->playlist[index_list].time_us),phlsctt->playlist[index_list].url);
			}
			if(index_list==phlsctt->playlist_index_out){
				ms_info("[o]%04d-%d-%s-%s",index_list,phlsctt->playlist[index_list].mediasequence,ms_num2str(  phlsctt->playlist[index_list].time_us),phlsctt->playlist[index_list].url);
			}
			ms_info("%04d-%d-%s-%s",index_list,phlsctt->playlist[index_list].mediasequence,ms_num2str(  phlsctt->playlist[index_list].time_us),phlsctt->playlist[index_list].url);
		}
		ms_info("-----------------------------------");
	}
}

static void hls_innerapi_playlistReset(HLSContext * phlsctt)
{
	phlsctt->playlist_index_in=0;
	phlsctt->playlist_index_out=0;
	phlsctt->segment_excpect=phlsctt->segment_head+1;
	phlsctt->playlist_index_stand=1;
}
static HLSPlaylist * hls_innerapi_playlistOut(HLSContext * phlsctt)
{
	 HLSPlaylist *pphlsctt=ms_null;
ms_reread:	 
	if(phlsctt->playlist_totalnum>0){
	//clear  pre data	
		if(ms_null!=phlsctt->pphlsctt_pre){
			ms_memset(phlsctt->pphlsctt_pre, 0,sizeof(HLSPlaylist))
		}
	//Get cur  data	
		pphlsctt=&phlsctt->playlist[phlsctt->playlist_index_out];
		phlsctt->pphlsctt_pre=&phlsctt->playlist[phlsctt->playlist_index_out];
	//put to next
		if(ms_noLess((++phlsctt->playlist_index_out), hlsin_msm3u8_maxsegment)){
			phlsctt->playlist_index_out-=hlsin_msm3u8_maxsegment;
		}
		phlsctt->playlist_totalnum--;
		ms_enInfo(DBG_HLSIN_PLAYLISTOUT,"playlist_totalnum:%d,playlist_index_in:%d,playlist_index_out:%d",
			phlsctt->playlist_totalnum,phlsctt->playlist_index_in,phlsctt->playlist_index_out);
	}
	if(0==ms_buflen(pphlsctt->url)
		||0==pphlsctt->time_us){
		phlsctt->unvalidplaylist_num+=1;
		if(phlsctt->unvalidplaylist_num>3){
			ms_waring("reset playlist val");
			hls_innerapi_playlistReset( phlsctt);
		}
		hls_innerapi_playlistPrintInfo(phlsctt);
		ms_warGoto(ms_reread,"Skip 1 segment");
	}else{
		phlsctt->unvalidplaylist_num=0;
	}
	return pphlsctt;
}
static ms_bool hls_innerapi_playlistDrop(HLSContext * phlsctt)
{
	if((phlsctt->list_size+4)<phlsctt->playlist_totalnum){
		ms_waring("playlist_totalnum(%d), list_size(%d),drop some segment",phlsctt->playlist_totalnum,phlsctt->list_size);
		ms_s32 index=0;
		ms_s32 num_drop=(phlsctt->playlist_totalnum-phlsctt->list_size);
		for(index=0;index<num_drop;index++){
			hls_innerapi_playlistOut( phlsctt);
		}
	}
}
static ms_bool hls_innerapi_playlistIn(HLSContext * phlsctt)
{
	ms_enInfo(DBG_HLSIN_PLAYLISTIN,"BF---playlist_index[o:s:i]%d,%d,%d,mediasequence is %d, excepet is %d",
		phlsctt->playlist_index_out,phlsctt->playlist_index_stand,phlsctt->playlist_index_in,phlsctt->segment_head,phlsctt->segment_excpect);
	if(0!=phlsctt->segment_excpect
		||0!=phlsctt->playlist_index_in
		||0!=phlsctt->playlist_index_out
		||0!=phlsctt->playlist_index_stand){
//drop segment too late		
		hls_innerapi_playlistDrop( phlsctt);
		if(ms_noLess(phlsctt->segment_head, phlsctt->segment_excpect)){
			ms_u32 playlist_index_in_tem=phlsctt->playlist_index_stand+(phlsctt->segment_head-phlsctt->segment_excpect);
			 if(ms_noLess(playlist_index_in_tem, hlsin_msm3u8_maxsegment)){	
				phlsctt->playlist_index_in=(playlist_index_in_tem%hlsin_msm3u8_maxsegment);
			}else{
				phlsctt->playlist_index_in=playlist_index_in_tem;
			}
			phlsctt->segment_excpect+=1;
			phlsctt->playlist_index_stand+=1;
		 	if(ms_noLess(phlsctt->playlist_index_stand, hlsin_msm3u8_maxsegment)){	
				phlsctt->playlist_index_stand-=hlsin_msm3u8_maxsegment;
			} 
		}else{
			ms_enInfo(DBG_HLSIN_PLAYLISTIN,"Same m3u8 file,mediasequence is %d,but excepet is %d",phlsctt->segment_head,phlsctt->segment_excpect);
			return ms_false;
		}
	}else{
		ms_enInfo(DBG_HLSIN_PLAYLISTIN,"reset val");
		hls_innerapi_playlistReset( phlsctt);
	}
	ms_enInfo(DBG_HLSIN_PLAYLISTIN,"AF---playlist_index[o:s:i]%d,%d,%d",phlsctt->playlist_index_out,phlsctt->playlist_index_stand,phlsctt->playlist_index_in);
	return ms_true;
}
static void hls_innerapi_playlistGetNum(HLSContext * phlsctt,ms_u32 n_segment)
{
	//playlist_index_int,n_segment,playlist_index_out:6,3,0
	//playlist_index_int,n_segment,playlist_index_out:5,3,6
	ms_enInfo(DBG_HLSIN_PLAYLISTINFO,"playlist_index[o:s:i]%d,%d,%d,n_segment:%d",phlsctt->playlist_index_out,phlsctt->playlist_index_stand,phlsctt->playlist_index_in,n_segment);
	ms_u32 playlist_index_in;
	if((phlsctt->playlist_index_in+n_segment)<hlsin_msm3u8_maxsegment){
		playlist_index_in=(phlsctt->playlist_index_in+n_segment);
	}else{
		playlist_index_in=(phlsctt->playlist_index_in+n_segment)-hlsin_msm3u8_maxsegment;
	}

	if(playlist_index_in<phlsctt->playlist_index_out){
		phlsctt->playlist_totalnum=playlist_index_in+(hlsin_msm3u8_maxsegment-phlsctt->playlist_index_out);
	}else{
		phlsctt->playlist_totalnum=playlist_index_in-phlsctt->playlist_index_out;
	}
}


static ms_s32 hls_innerapi_buildUrl(ms_string tbuf,ms_string urlout,HLSContext * phlsctt,ms_bool flag_segment)
{
	ms_bool is_newRequesetKeepConnection=ms_false;
	if(ms_strncmp_seq(tbuf, "http://")||ms_strncmp_seq(tbuf, "https://")){
		ms_strcpy(urlout, tbuf);
		//由于指定了http地址，分片可能无法重复连接
		is_newRequesetKeepConnection=ms_false;
	}else if(ms_strncmp_seq(tbuf, "./")){
		ms_sprintfs(urlout, "%s/%s", phlsctt->path,&tbuf[2]);
		is_newRequesetKeepConnection=ms_true;
	}else if(ms_true==msstr_api_isCasestr(tbuf, phlsctt->path_info.path)||(ms_strncmp_seq(tbuf, "/"))	){
		if(phlsctt->path_info.port>0){
			ms_sprintfs(urlout, "%s://%s:%d/%s", msptc_api_getPtcName(msptc_msoshls),phlsctt->path_info.hostname, phlsctt->path_info.port,tbuf);
		}else{
			ms_sprintfs(urlout, "%s://%s/%s", msptc_api_getPtcName(msptc_msoshls), phlsctt->path_info.hostname,tbuf);
		}
		is_newRequesetKeepConnection=ms_true;
	}else{
		ms_sprintfs(urlout, "%s/%s", phlsctt->path,tbuf);
		is_newRequesetKeepConnection=ms_true;
	}

	if(ms_true==flag_segment){
		phlsctt->urlctt_segment.is_newRequesetKeepConnection=is_newRequesetKeepConnection;
	}else{
		phlsctt->urlctt_m3u8.is_newRequesetKeepConnection=is_newRequesetKeepConnection;
	}
}
static ms_s32 hls_innerapi_paraseXStreamInf(ms_string tbuf,HLSXSTREAMContext *pxstrem_ctt)
{
//#EXT-X-STREAM-INF:RESOLUTION=1280x720,FRAME-RATE=29.970,CODECS="acvc1.4d001f,mp4a.40.2",AVERAGE-BANDWIDTH=2710000,BANDWIDTH=3390000
	ms_string  str_array_ret[1024];
	int xstreaminf_num=msstr_api_split(tbuf, ",", str_array_ret);
	ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf]line num:%d", xstreaminf_num);
	int item_index=0;
	for(item_index=0;item_index<xstreaminf_num;item_index++){
		ms_string  str_array[1024];
		ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf]:%s",str_array_ret[item_index]);
		if(msstr_api_split(str_array_ret[item_index], "=", str_array)>1){
			ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf]:%s,%s",str_array[0],str_array[1]);
			if(ms_true==msstr_api_isCasestr(str_array[0],"RESOLUTION")){
				ms_strcpy(pxstrem_ctt->resolution, str_array[1]);
				ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf]:------resolution=%s",pxstrem_ctt->resolution);
			}else if(ms_true==msstr_api_isCasestr(str_array[0],"FRAME-RATE")){
				pxstrem_ctt->frame_rate=atof(str_array[1]);
				ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf]:------frame_rate=%f",pxstrem_ctt->frame_rate);
			}else if(ms_true==msstr_api_isCasestr(str_array[0],"CODECS")){
				ms_strcpy(pxstrem_ctt->codes, str_array[1]);
				ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf]:------codes=%s",pxstrem_ctt->codes);
			}else if(ms_true==msstr_api_isCasestr(str_array[0],"AVERAGE-BANDWIDTH")){
				pxstrem_ctt->average_bandwidth=ms_atoi(str_array[1]);
				ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf]:------average_bandwidth=%u",pxstrem_ctt->average_bandwidth);
			}else if(ms_true==msstr_api_isCasestr(str_array[0],"BANDWIDTH")){
				pxstrem_ctt->bandwidth=ms_atoi(str_array[1]);
				ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf]:------bandwidth=%u",pxstrem_ctt->bandwidth);
			}
		}
	}		
}
static void hls_innerapi_getOutPath(URLContext *s)
{
	HLSContext * phlsctt=s->priv_data;
	char *url=s->url;
	ms_getHlsPath(s->url, s->opt.hls.vodpath, phlsctt->path);
}
static void hls_innerapi_getUrlInfo(HLSContext * phlsctt)
{
	ms_s08 tmbuf[mscfg_maxlen_url]={0};
	if(phlsctt->urlctt_m3u8.flag_location){
		ms_strcpy(tmbuf, phlsctt->urlctt_m3u8.location);
	}else{
		ms_strcpy(tmbuf, phlsctt->urlctt_m3u8.url);
	}

	ms_string str_array_item[256];
	ms_u32 num=msstr_api_split(tmbuf, "?", str_array_item);	//1.ts-udp://224.2.2.2:8880;2.ts-udp://224.2.2.2:8881;

	ms_string ptmbuf=ms_null;
	if(num>0){
		ptmbuf=str_array_item[0];
	}else{
		ptmbuf=tmbuf;
	}
	ms_u32 urllen=ms_buflen(ptmbuf);
	for(;urllen>0;urllen--){
		if('/'==ptmbuf[urllen]){
			ptmbuf[urllen]=0;
			break;
		}
		ptmbuf[urllen]=0;
	}
	ms_strcpy(phlsctt->path, ptmbuf);
	//ms_debug("location path:%s",phlsctt->path);
	msptc_api_urlSplit_urlinfo(&phlsctt->path_info, phlsctt->path);
}
static ms_s32 hls_innerapi_m3u8Parase(URLContext *s,HLSContext * phlsctt)
{
	ms_s32 ret=0;
	ms_u32 n_segment=0;
	HTTPContext * phttp_ctt=ms_null;

/*获取M3U8内容*/	
ms_reopen:
	phlsctt->flag_hasxstream=ms_false;
	ms_enInfo(DBG_HLSIN_PLAYLIST,"url_open:%s",phlsctt->urlctt_m3u8.url);
	phlsctt->urlctt_m3u8.is_newRequesetKeepConnection=ms_true;//设置使用同一个连接读取M3U8文件
	if(phlsctt->ptlHttp->url_open(&phlsctt->urlctt_m3u8)<0){
		ms_errRet(-1, "url_open failed");
	}
	phttp_ctt=(HTTPContext * )phlsctt->urlctt_m3u8.priv_data;

	ms_s32 m3u8_buf_size=(phttp_ctt->replyfiledata_len+10);
	if(phttp_ctt->content_type==content_type_mpegurl){
		m3u8_buf_size=(phttp_ctt->content_len+10);
	}
	ms_pbyte m3u8_buf=ms_malloc(m3u8_buf_size,"hls_m3u8Buf"); 
	if(NULL==m3u8_buf){ 
		phlsctt->ptlHttp->url_close(&phlsctt->urlctt_m3u8);
		ms_errRet(-2,"Malloc %s failed,please check the memory","hls_m3u8Buf"); 
	}
	ms_enInfo(DBG_HLSIN_PLAYLIST,"url_read:%s",phlsctt->urlctt_m3u8.url);
	ms_s32 len_m3u8=phlsctt->ptlHttp->url_read(&phlsctt->urlctt_m3u8,m3u8_buf,m3u8_buf_size);
	//ms_enInfo(DBG_HLSIN_PLAYLIST,"url_close:%s",phlsctt->urlctt_m3u8.url);
	//phlsctt->ptlhttp->url_close(&phlsctt->urlctt_m3u8);
	ms_enInfo(DBG_HLSIN_PLAYLIST,"Update playlist");
	ms_enInfo(DBG_HLSIN_PLAYLIST,"m3u8_buf:\r\n%s",m3u8_buf);

/*获取URL地址相关信息*/
	hls_innerapi_getUrlInfo(phlsctt);

/*解析M3U8内容*/	
	char tbuf[1024]={0};
	ms_ps08 p =m3u8_buf;	
	msstr_api_getLine(tbuf, sizeof(tbuf), (const char **)&p);
	//判断头部信息
	if(msstr_api_isCasestr(tbuf, m3u8_tag) ==0){
		ret=-1;
		ms_errGoto(ms_end,"The first line contains '%s' and no M3U8 header tag (%s) found. Is this really an M3U8 file?",tbuf,m3u8_tag);
	}
	ms_enDbg(DBG_HLS,"BF---playlist_index_in,playlist_index_out,playlist_index_stand,playlist_totalnum:%d,%d,%d,%d",
		phlsctt->playlist_index_in,phlsctt->playlist_index_out,phlsctt->playlist_index_stand,phlsctt->playlist_totalnum);
	ms_bool flag_find_mediaSequence=ms_false;
	while(0!=*p){
		ms_memset(tbuf,0,sizeof(tbuf));
		msstr_api_getLine(tbuf, sizeof(tbuf), (const char **)&p);
		ms_enVerbose(DBG_HLS,"tbuf:%s",tbuf);
		if(msstr_api_isCasestr(tbuf, m3u8_ver) !=0){
			phlsctt->version=ms_atoi(&tbuf[ms_buflen(m3u8_ver)+1]);
			ms_enVerbose(DBG_HLS,"version:%d",phlsctt->version);
		}else if(msstr_api_isCasestr(tbuf, m3u8_allowCache) !=0){
			if(ms_strncmp_saeq((&tbuf[ms_buflen(m3u8_allowCache)+1]), "YES")){
				phlsctt->allowcache=ms_true;
			}else{
				phlsctt->allowcache=ms_false;
			}
			ms_enVerbose(DBG_HLS,"allowcache:%d",phlsctt->allowcache);
		}else if(msstr_api_isCasestr(tbuf, m3u8_targetDuration) !=0){
			phlsctt->time=atof(&tbuf[ms_buflen(m3u8_targetDuration)+1]);
	
			double time_d=(phlsctt->time)*1000*1000; 	
			phlsctt->time_us=(ms_u64)time_d;
			ms_enVerbose(DBG_HLS,"time:%f---%s",phlsctt->time, ms_num2str(phlsctt->time_us));
			if(ms_false==msstr_api_isCasestr(phlsctt->hls_info, "hls_time")){
				ms_s08 tbuf_case[512]={0};
				ms_strcats(tbuf_case,phlsctt->hls_info, "#hls_time(%f)", phlsctt->time);
			}
		}else if(msstr_api_isCasestr(tbuf, m3u8_mediaSequence) !=0){
			if(ms_false==flag_find_mediaSequence){
				flag_find_mediaSequence=ms_true;
				phlsctt->segment_head=ms_atoi(&tbuf[ms_buflen(m3u8_mediaSequence)+1]);
				ms_enVerbose(DBG_HLS,"mediasequence:%d",phlsctt->segment_head);
				//如果当前是旧的M3U8文件，则不进行处理
				if(ms_false==hls_innerapi_playlistIn( phlsctt)){
					ms_enVerbose(DBG_HLS,"hls_innerapi_playlistIn failed");
					ret=-2;
					goto ms_end;
				}
			}
		}else if(msstr_api_isCasestr(tbuf, m3u8_streamInf) !=0){
			if(phlsctt->xstream_num<HLSIN_MAX_XSTREAM){
				ms_enDbg(DBG_HLSIN_XSTREAM,"xstream_num----%d",phlsctt->xstream_num);
				hls_innerapi_paraseXStreamInf( tbuf,&phlsctt->xstrem_ctt[phlsctt->xstream_num]);
				memset(tbuf,0,sizeof(tbuf));
				msstr_api_getLine(tbuf, sizeof(tbuf), (const char **)&p);
				phlsctt->flag_hasxstream=ms_true;
				hls_innerapi_buildUrl(tbuf, phlsctt->xstrem_ctt[phlsctt->xstream_num].url,phlsctt,ms_false);
				ms_enDbg(DBG_HLSIN_XSTREAM,"----%s",phlsctt->xstrem_ctt[phlsctt->xstream_num].url);
				phlsctt->xstream_num++;
			}else{
				ms_waring("xstream max numis %d,drop it",HLSIN_MAX_XSTREAM);
			}
		}else if(msstr_api_isCasestr(tbuf, m3u8_inf) !=0){
			float time=atof(&tbuf[ms_buflen(m3u8_inf)+1]);
			double time_d=(time)*1000*1000; 	
			
			ms_u32 index=0;
			 if(ms_noLess((phlsctt->playlist_index_in+n_segment), hlsin_msm3u8_maxsegment)){	
				index= phlsctt->playlist_index_in+n_segment-hlsin_msm3u8_maxsegment;
			}else{
				index=phlsctt->playlist_index_in+n_segment;
			}
			ms_enDbg(DBG_HLS,"playlist_index_in,n_segment,index:%d,%d,%d",phlsctt->playlist_index_in,n_segment,index);
			phlsctt->playlist[index].mediasequence=phlsctt->segment_head+n_segment;
			phlsctt->playlist[index].time_us=(ms_u64)time_d;
			memset(tbuf,0,sizeof(tbuf));
			msstr_api_getLine(tbuf, sizeof(tbuf), (const char **)&p);
			while(ms_strncmp_seq(tbuf, "#EXT")){
				msstr_api_getLine(tbuf, sizeof(tbuf), (const char **)&p);
			}
			hls_innerapi_buildUrl(tbuf, phlsctt->playlist[index].url, phlsctt,ms_true);
			n_segment++;
		}else if(msstr_api_isCasestr(tbuf, m3u8_endList) !=0){
			//点播分片存在结束符，直播不存在
			phlsctt->flag_finished=ms_true;
		}
	}	

	/*同一个地址有多个URL的，采用码率最小的那个*/
	if(ms_true==phlsctt->flag_hasxstream){
		ms_u32 index=0;
		ms_u32 min_bandwidth=0;
		ms_u32 find_index=0;
		ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf] xstream_num:%d", phlsctt->xstream_num);
		//找码率最小的流
		for(index=0;index<phlsctt->xstream_num;index++){
			ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf] bandwidth,min_bandwidth:%u,%u", phlsctt->xstrem_ctt[index].bandwidth,min_bandwidth);
			if(phlsctt->xstrem_ctt[index].bandwidth<min_bandwidth
				||0==min_bandwidth){
				find_index=index;
				min_bandwidth=phlsctt->xstrem_ctt[index].bandwidth;
				ms_enDbg(DBG_HLSIN_XSTREAM,"[xstreaminf] min_bandwidth:%u", min_bandwidth);
			}
		}
		ms_strcpy(phlsctt->urlctt_m3u8.url,phlsctt->xstrem_ctt[find_index].url);
		phlsctt->urlctt_m3u8.flag_location=ms_false;
		if(ms_false==phlsctt->urlctt_m3u8.is_newRequesetKeepConnection){
			phlsctt->ptlHttp->url_close(&phlsctt->urlctt_m3u8);
		}
		ms_infoGoto(ms_reopen, "reopen:%s,use xstream_index:%d",phlsctt->urlctt_m3u8.url,find_index);
	}
	phlsctt->list_size=n_segment;
	hls_innerapi_playlistGetNum(phlsctt,n_segment);
	ms_enDbg(DBG_HLS,"AF---playlist_index_in,playlist_index_out,playlist_index_stand,n_segment,playlist_totalnum:%d,%d,%d,%d,%d",
		phlsctt->playlist_index_in,phlsctt->playlist_index_out,phlsctt->playlist_index_stand,n_segment,phlsctt->playlist_totalnum);
ms_end:	
	#if DBG_HLSIN_PLAYLISTINFO
		hls_innerapi_playlistPrintInfo(phlsctt);
	#endif
	ms_deMalloc(m3u8_buf);
	return ret;
}
static void hls_innerapi_getProgramName(URLContext *s)
{
	HLSContext * phlsctt=s->priv_data;
	char *url=s->url;
	char *pvodpath=s->opt.hls.vodpath;
	ms_getHlsName(url, pvodpath, phlsctt->programname);
}


static ms_void hls_innerapi_m3u8Update(HLSContext * phlsctt)
{
	/*	list_size=3
		segment_tail:		0,1,2,3,4,5
		segment_head:	0,0,0,0,1,2
	*/
//Add new segment
	ms_sprintfs(phlsctt->urlctt_segment.url, "%s/%s%d.ts", phlsctt->path,phlsctt->programname,phlsctt->segment_tail);
//Delete old segment
	phlsctt->segment_delete+=1;
	if(ms_noLess(phlsctt->segment_delete , HLSOUT_SEGMENT_LISTSIZE(phlsctt->list_size))){
		phlsctt->segment_delete=0;
	}
	ms_string  pfilename=&phlsctt->list_segment[phlsctt->segment_delete*HLSOUT_SEGMENT_URLLEN];
	if(0<ms_buflen(pfilename)	){
		if (unlink(pfilename) < 0){
			if (rmdir(pfilename) < 0){
				ms_error("file_delete(%s)  failed(%d,%s)", pfilename, errno,strerror(errno) );
			}
		}
	}
//Update segment_tail and segment_head
#if HLSOUT_SEGMENTING_INM3U8
	phlsctt->segment_tail+=1;
	if(ms_noLess(phlsctt->segment_tail,msm3u8_maxsqencenum)){
		phlsctt->segment_tail=0;
	}
#endif
	if(ms_false==phlsctt->flag_started_list){
		if(  ms_noLess(phlsctt->segment_tail , phlsctt->segment_head)
			&&(ms_noMore(phlsctt->list_size,(phlsctt->segment_tail-phlsctt->segment_head)))){
			phlsctt->flag_started_list=ms_true ;
		}
	}else{
		phlsctt->segment_head+=1;
		if(ms_noLess(phlsctt->segment_head,msm3u8_maxsqencenum)){
			phlsctt->segment_head=0;
		}
	}
	ms_enInfo(DBG_HLSOUT_PLAYLISTINFO,"segment_tail,segment_head,flag_started_list:%d,%d,%d",
		phlsctt->segment_tail,phlsctt->segment_head,phlsctt->flag_started_list);
	ms_strcpy(&phlsctt->list_segment[phlsctt->segment_delete*HLSOUT_SEGMENT_URLLEN], phlsctt->urlctt_segment.url);
//Update m3u8
	phlsctt->ptlfile->priv_func.file.url_seek(&phlsctt->urlctt_m3u8,0,SEEK_SET);	
	char m3u8_buf[1024]={0};
	char tmpbuf[1024]={0};
	ms_strcats(tmpbuf, m3u8_buf, "%s\r\n", m3u8_tag);
	ms_strcats(tmpbuf, m3u8_buf, "%s:%d\r\n",m3u8_ver,phlsctt->version);
	ms_strcats(tmpbuf, m3u8_buf, "%s:%s\r\n",m3u8_allowCache,(ms_false==phlsctt->allowcache) ? "NO" : "YES");
	ms_strcats(tmpbuf, m3u8_buf, "%s:%d\r\n",m3u8_targetDuration,(ms_s32)phlsctt->time);
#if 1	
	ms_strcats(tmpbuf, m3u8_buf, "%s:%d\r\n",m3u8_mediaSequence,phlsctt->segment_head);
	ms_u32 index=0;
	if(ms_noLess(phlsctt->segment_tail,phlsctt->segment_head)){
		for(index=phlsctt->segment_head;index<(phlsctt->segment_tail);index++){
			ms_strcats(tmpbuf, m3u8_buf, "%s:%f,\r\n",m3u8_inf,phlsctt->time);
			ms_strcats(tmpbuf, m3u8_buf, "%s%d.ts\r\n",phlsctt->programname,index);
		}
	}else{
		for(index=phlsctt->segment_head;index<(msm3u8_maxsqencenum);index++){
			ms_strcats(tmpbuf, m3u8_buf, "%s:%f,\r\n",m3u8_inf,phlsctt->time);
			ms_strcats(tmpbuf, m3u8_buf, "%s%d.ts\r\n",phlsctt->programname,index);
		}
		for(index=0;index<phlsctt->segment_tail;index++){
			ms_strcats(tmpbuf, m3u8_buf, "%s:%f,\r\n",m3u8_inf,phlsctt->time);
			ms_strcats(tmpbuf, m3u8_buf, "%s%d.ts\r\n",phlsctt->programname,index);
		}
	}
#else
	ms_u32 index=0;
	if(ms_noLess(phlsctt->segment_tail,phlsctt->segment_head)){
		for(index=phlsctt->segment_head;index<(phlsctt->segment_tail);index++){
			ms_strcats(tmpbuf, m3u8_buf, "%s:%d\r\n",m3u8_mediaSequence,index);
			ms_strcats(tmpbuf, m3u8_buf, "%s:%f,\r\n",m3u8_inf,phlsctt->time);
			ms_strcats(tmpbuf, m3u8_buf, "%s%d.ts\r\n",phlsctt->programname,index);
		}
	}else{
		for(index=phlsctt->segment_head;index<(msm3u8_maxsqencenum);index++){
			ms_strcats(tmpbuf, m3u8_buf, "%s:%d\r\n",m3u8_mediaSequence,index);
			ms_strcats(tmpbuf, m3u8_buf, "%s:%f,\r\n",m3u8_inf,phlsctt->time);
			ms_strcats(tmpbuf, m3u8_buf, "%s%d.ts\r\n",phlsctt->programname,index);
		}
		for(index=0;index<phlsctt->segment_tail;index++){
			ms_strcats(tmpbuf, m3u8_buf, "%s:%d\r\n",m3u8_mediaSequence,index);
			ms_strcats(tmpbuf, m3u8_buf, "%s:%f,\r\n",m3u8_inf,phlsctt->time);
			ms_strcats(tmpbuf, m3u8_buf, "%s%d.ts\r\n",phlsctt->programname,index);
		}
	}
#endif
	ms_enInfo(DBG_HLSOUT_PLAYLISTINFO,"\r\n%s",m3u8_buf);
	phlsctt->ptlfile->url_write(&phlsctt->urlctt_m3u8,m3u8_buf,ms_buflen(m3u8_buf));
#if !HLSOUT_SEGMENTING_INM3U8
	phlsctt->segment_tail+=1;
	if(ms_noLess(phlsctt->segment_tail,msm3u8_maxsqencenum)){
		phlsctt->segment_tail=0;
	}
#endif
}
static void hls_m3u8Parase(void *arg)
{
	URLContext *s=(URLContext *)arg;
	if(0==s->is_connected){
		return;
	}
	msthread_api_setName2("hlsParse(%s)",s->url);
	HLSContext * phlsctt=(HLSContext *)s->priv_data;
	while(1){
		if(mstime_api_counterAsyncSec((time_t *)&phlsctt->timep_m3u8Parse,HLSIN_PARASEM3U8_INTERVALTIME)){
			hls_innerapi_m3u8Parase(s,phlsctt);
		}
		ms_sleep(1);
		if(ms_true==phlsctt->flag_cmdstop_m3u8Parase||ms_true==s->is_cmdstop){
			ms_debug("stop thread:parase playlist");
			break;
		}
	}
	phlsctt->flag_cmdstop_m3u8Parase=ms_false;
}
static int hls_open(URLContext *s)
{
	if(ms_true==s->is_connected){
		return 0;
	}
	ms_mallocDes_retErr(-1, s->priv_data, sizeof(HLSContext), "HLSContext",s->url);
	HLSContext * phlsctt=s->priv_data;
	
	ms_debug("flags:%d", s->flags);
	/*HLS输出*/
	if(s->flags&FLAG_WRITE){	
		phlsctt->ptlfile=msptc_api_matchByPtcindex(msptc_file);
	//获取HLS切片生成的目录
		hls_innerapi_getOutPath(s);
		ms_debug("path:%s", phlsctt->path);
	//获取HLS切片的名称
		hls_innerapi_getProgramName(s);
		ms_debug("programname:%s", phlsctt->programname);
	//初始化切片参数	
		phlsctt->flag_started_list=ms_false;
		phlsctt->version=3;
		phlsctt->allowcache=ms_true;
	//切片数量
		phlsctt->list_size=(0==s->opt.hls.list_size) ? 3 : s->opt.hls.list_size;
		if(ms_noLess(HLSOUT_SEGMENT_LISTSIZE(phlsctt->list_size),hlsin_msm3u8_maxsegment)){
			ms_waring("list_size(%d) is too large",phlsctt->list_size);
			phlsctt->list_size=3;
		}
		ms_u32 maxnum_maxsegment=HLSOUT_SEGMENT_LISTSIZE(phlsctt->list_size);
		phlsctt->list_segment=(ms_u08 *)ms_malloc(sizeof(ms_u08)*maxnum_maxsegment*HLSOUT_SEGMENT_URLLEN,"hls_list_segment");
		if(NULL==phlsctt->list_segment){
			ms_errGoto(ms_fail,"ms_malloc list_segment faild(%d,%s)",errno,strerror(errno));
		}
		//切片时间
		phlsctt->time=(0.0==s->opt.hls.time) ? 3.0 : s->opt.hls.time;
		double time_d=phlsctt->time*1000*1000;
		phlsctt->time_us=(ms_u64)time_d;
		ms_debug("hls-list_size:%d,time:%f", phlsctt->list_size,phlsctt->time);
	//打开M3U8文件的描述符
		ms_sprintfs(phlsctt->urlctt_m3u8.url, "%s/%s",phlsctt->path,s->url);
		phlsctt->urlctt_m3u8.flags|=FLAG_NOCHECKEXSIT;
		if(phlsctt->ptlfile->url_open(&phlsctt->urlctt_m3u8)<0){
			ms_errGoto(ms_fail, "open %s failed(%d,%s)",phlsctt->urlctt_m3u8.url,errno,strerror(errno));
		}
	}else{
		phlsctt->playlist=(HLSPlaylist *)ms_malloc(sizeof(HLSPlaylist)*hlsin_msm3u8_maxsegment,"hls_playlist");
		if(NULL==phlsctt->playlist){
			ms_errGoto(ms_fail,"ms_malloc playlist faild(%d,%s)",errno,strerror(errno));
		}
	//参数初始化	
		phlsctt->ptlHttp=msptc_api_matchByPtcindex(msptc_http);
		phlsctt->urlctt_m3u8.ifcIn=s->ifcIn;
		ms_strcpy(phlsctt->urlctt_m3u8.url,(ms_true==s->flag_location)?s->location:s->url);
/*
Accept
	0-Accept: *
	1-Accept: text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8
range_type
	0-Range: bytes=0-
	*-Range: bytes=0-%d
connect_type
	0-Connection: close
	1-Connection: keep-alive*/		
		phlsctt->urlctt_m3u8.opt.http.accept_type=1;
		phlsctt->urlctt_m3u8.opt.http.range_type=0;
		phlsctt->urlctt_m3u8.opt.http.connect_type=1;
	//创建定时任务，用于读取和解析M3U8文件，更新播放列表	
		if(msthread_api_create(&phlsctt->tdM3u8Parase, "m3u8parase", hls_m3u8Parase, s)<0){
			ms_errGoto(ms_fail, "create thread %s failed(%d,%s)","m3u8parase",errno,strerror(errno));
		}
	//置位为可以读取切片
		phlsctt->flag_next=ms_true;
	}
	s->is_connected=ms_true;
	return 0;
ms_fail:
	s->is_connected=ms_false;
	if(s->flags&FLAG_WRITE){
		ms_deMalloc(phlsctt->list_segment);
	}else{
		ms_deMalloc(phlsctt->playlist);
	}
	ms_deMalloc(phlsctt);
	return -1;

}
static int hls_read(URLContext *s, unsigned char *buf, ms_s32 size)
{
	if(0==s->is_connected){
		return -1;
	}
	HLSContext * phlsctt=(HLSContext *)s->priv_data;
	ms_s32 len=0;
	HTTPContext * phttp_ctt=(HTTPContext * )phlsctt->urlctt_segment.priv_data;
	ms_u32 try_read_time=0;
ms_reread:	
	if(ms_true==s->is_cmdstop){
		phlsctt->ptlHttp->url_close(&phlsctt->urlctt_segment);
		ms_enInfo(DBG_HLSIN_READ,"[%s] cmdstop",phlsctt->pplaylist_cur->url);
		return 0;
	}
	if(ms_true==phlsctt->flag_next){
		if(0==phlsctt->playlist_totalnum){
			return -1;
		}else{
			phlsctt->recv_time_base=mstime_api_us();
			if(ms_false==phlsctt->urlctt_segment.is_connected){
				ms_memset(&phlsctt->urlctt_segment, 0, sizeof(URLContext));
			}
			phlsctt->urlctt_segment.ifcIn=s->ifcIn;
			phlsctt->urlctt_segment.opt.http.range_type=1;
			//phlsctt->urlctt_segment.urlctt_opt.http_opt.range_byte=size;
			phlsctt->urlctt_segment.opt.http.accept_type=0;
			phlsctt->urlctt_segment.opt.http.connect_type=1;
			phlsctt->urlctt_segment.opt.http.rw_timeout=300;
			phlsctt->pplaylist_cur=hls_innerapi_playlistOut(phlsctt);
			if(ms_null==phlsctt->pplaylist_cur){
				phlsctt->flag_finished=ms_false;
				goto reread_playlist;
			}
			ms_sprintfs(phlsctt->urlctt_segment.url, "%s",phlsctt->pplaylist_cur->url);
			ms_enInfo(DBG_HLSIN_READ,"BF--open=>%s,time:%s",phlsctt->urlctt_segment.url,ms_num2str(phlsctt->pplaylist_cur->time_us));
			//此处打开可能是新建一个连接，也有可能是在原有连接上面打开一个新的请求
			if(phlsctt->ptlHttp->url_open(&phlsctt->urlctt_segment)){
				goto reread_playlist;
			}
			phttp_ctt=(HTTPContext * )phlsctt->urlctt_segment.priv_data;
			ms_enInfo(DBG_HLSIN_READ,"AF--open=>%s,time:%s(content_len:%d),fd=%d",
				phlsctt->urlctt_segment.url,ms_num2str(phlsctt->pplaylist_cur->time_us),phttp_ctt->content_len,phttp_ctt->tcpctt.fd);
			phlsctt->recv_segment_len=0;
			phlsctt->flag_next=ms_false;
		}
	}
	//ms_enVerbose(DBG_HLS, "Read hls data");
	if(ms_true==phlsctt->urlctt_segment.is_connected&&ms_false==phlsctt->flag_next){
		len=phlsctt->ptlHttp->url_read(&phlsctt->urlctt_segment,buf,size);
		//ms_enInfo(DBG_HLSIN_READ,"read len,content_len:%d,%d,need_read:%d",len,phttp_ctt->content_len,(phttp_ctt->content_len-phlsctt->content_len));
		if(msepoll_ret_abnormal_connection==len){
			ms_errGoto(reread_playlist, "sockcet maybe error,url:%s",s->url);
		}else if(!(0<len)){
			ms_s64 time_cha=(mstime_api_us()-phlsctt->recv_time_base);
			ms_s64 time_timeout=(phlsctt->pplaylist_cur->time_us*10);
			//ms_exit(1);
			if((ms_null!=phttp_ctt)&&(phttp_ctt->content_len>0)&&(phlsctt->recv_segment_len>0)&&(phttp_ctt->content_len!=phlsctt->recv_segment_len)){
				if(  time_cha> time_timeout){
					ms_warGoto(reread_playlist, "timeout----time_cha,time_timeout:%s,%s,data(except)%d-(actual)%d=%d[%s]",
						ms_num2str(time_cha),ms_num2str(time_timeout),
						phttp_ctt->content_len,phlsctt->recv_segment_len,(phttp_ctt->content_len-phlsctt->recv_segment_len),s->url);
				}
				ms_enDbg(DBG_HLS,"len(%d),try_read_time:%d--try read again,time(%s,%s),data(except)%d-(actual)%d=%d,[%s]",len,(++try_read_time),
					ms_num2str(time_cha),ms_num2str((phlsctt->pplaylist_cur->time_us)),
					phttp_ctt->content_len,phlsctt->recv_segment_len,(phttp_ctt->content_len-phlsctt->recv_segment_len),s->url);
				if(try_read_time>3){
					ms_warGoto(ms_end,"len(%d),try_read_time:%d--try read again,time(%s,%s),data(except)%d-(actual)%d=%d,[%s]",len,(++try_read_time),
						ms_num2str(time_cha),ms_num2str((phlsctt->pplaylist_cur->time_us)),
						phttp_ctt->content_len,phlsctt->recv_segment_len,(phttp_ctt->content_len-phlsctt->recv_segment_len),s->url);
				}
				goto ms_reread;
			}else{
reread_playlist:	
				if(phlsctt->pplaylist_cur->time_us<(mstime_api_us()-phlsctt->recv_time_base)){
					ms_waring("cur segment-time:%s,cost-time:%s ,It may cause a lower FIFO overflow",
						ms_num2str(phlsctt->pplaylist_cur->time_us),ms_num2str(mstime_api_us()-phlsctt->recv_time_base));
						if(ms_false==msstr_api_isCasestr(phlsctt->hls_info, "hls_costtime_long")){
							ms_s08 tbuf[512]={0};
							ms_strcats(tbuf,phlsctt->hls_info, "#%s", "hls_costtime_long");
						}
				}
				ms_enInfo(DBG_HLSIN_READ,"cur segment-time:%s,cost-time:%s,close(%s-fd=%d)read next ",
					ms_num2str(phlsctt->pplaylist_cur->time_us),ms_num2str(mstime_api_us()-phlsctt->recv_time_base),
					phlsctt->urlctt_segment.url,phttp_ctt->tcpctt.fd);
				if(ms_false==phlsctt->urlctt_segment.is_newRequesetKeepConnection){
					phlsctt->ptlHttp->url_close(&phlsctt->urlctt_segment);
				}
				phlsctt->recv_time_base=0;
				phlsctt->flag_next=ms_true;
				len=0;
				goto ms_reread;
			}
		}else{
			if(len>0){
				phlsctt->recv_segment_len+=len;
			}
		}
	}
ms_end:
	//ms_enVerbose(DBG_HLS, "Read hls data-------len:%d",len);
	return len;
}
static int hls_write(URLContext *s, unsigned char *buf, int size)
{
	if(ms_false==s->is_connected){
		return -1;
	}
	HLSContext * phlsctt=(HLSContext *)s->priv_data;

	//open new segment
	if(mstime_api_counterAsyncUs((ms_u64 *)&phlsctt->timep_newsegment,(phlsctt->time_us-300))){
		//close old segment
		phlsctt->ptlfile->url_close(&phlsctt->urlctt_segment);
		//update m3u8
		hls_innerapi_m3u8Update(phlsctt);
		//open new segment
		phlsctt->urlctt_segment.flags|=FLAG_NOCHECKEXSIT;
		phlsctt->ptlfile->url_open(&phlsctt->urlctt_segment);
	}
	return phlsctt->ptlfile->url_write(&phlsctt->urlctt_segment,buf,size);
}

static int hls_close(URLContext *s)
{
	HLSContext * phlsctt=(HLSContext *)s->priv_data;
	if(0==s->is_connected){
		return 0;
	}
	s->is_cmdstop=ms_true;
	if(s->flags&FLAG_WRITE){
		phlsctt->ptlfile->url_close(&phlsctt->urlctt_segment);
		phlsctt->ptlfile->url_close(&phlsctt->urlctt_m3u8);
		ms_byte cmdbuf[mscfg_maxlen_url]={0};
		ms_cmd(cmdbuf, "rm -fr %s", phlsctt->path);
	}else{
		phlsctt->flag_cmdstop_m3u8Parase=ms_true;
		time_t sys_base=mstime_api_sec();
		ms_debug("send stop thread:parase playlist");
		while(ms_true==phlsctt->flag_cmdstop_m3u8Parase){
			ms_msleep(100);
			if(ms_true==mstime_api_counterAsyncSec(&sys_base, ms_seconds(5))){
				break;
			}
		}
		msthread_api_destroy(&phlsctt->tdM3u8Parase);
		phlsctt->ptlHttp->url_close(&phlsctt->urlctt_segment);
		phlsctt->ptlHttp->url_close(&phlsctt->urlctt_m3u8);
	}
	if(s->flags&FLAG_WRITE){
		ms_deMalloc(phlsctt->list_segment);
	}else{
		ms_deMalloc(phlsctt->playlist);
	}
	ms_deMalloc(phlsctt);
	s->is_connected=ms_false;
	s->is_cmdstop=ms_false;
	return 0;
}
static ms_string hls_info(URLContext *s)
{
	HLSContext * phlsctt=(HLSContext *)s->priv_data;
	if(0==s->is_connected){
		return ms_null;
	}
	return phlsctt->hls_info;
}
static ms_u32 hls_playlist_totalnum(URLContext *s)
{
	HLSContext * phlsctt=(HLSContext *)s->priv_data;
	if(0==s->is_connected){
		return 0;
	}
	return phlsctt->playlist_totalnum;
}
static ms_u32 hls_list_size(URLContext *s)
{
	HLSContext * phlsctt=(HLSContext *)s->priv_data;
	if(0==s->is_connected){
		return 0;
	}
	return phlsctt->list_size;
}

static ms_u32 hls_m3u8_parase(URLContext *s)
{
	HLSContext * phlsctt=(HLSContext *)s->priv_data;
	if(0==s->is_connected){
		return 0;
	}
	hls_innerapi_m3u8Parase(s,phlsctt);
	return 0;
}

URLProtocol ffurl_msoshls_protocol={
	.nameDes	= msptc_getPtcNameDes(msptc_msoshls),
    .url_open	= hls_open,
    .url_read	= hls_read,
    .url_write	= hls_write,
    .url_close	= hls_close,
    .url_info	= hls_info,
    .priv_func={
    	.hls.playlist_totalnum=hls_playlist_totalnum,
    	.hls.list_size=hls_list_size,
    	.hls.m3u8_parase=hls_m3u8_parase,
    },
    .flags		=STREAM_LIVE_VOD,
    .next	=NULL,
};
#undef HLS_C
